﻿#include "FITKAcousticsVTKGraphObjectModel.h"
#include "FITKAcousticsVTKGraphActor.h"

// VTK
#include <vtkObject.h>
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkIdList.h>
#include <vtkCellType.h>
#include <vtkCellArray.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkPolygon.h>
#include <vtkPolyDataNormals.h>

// Graph 
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKColorMap.h"
#include "FITKAcousticsVTKGraphObjectSelect.h"

// Data
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoCommand.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoShapeAgent.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKVirtualTopoManager.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshVS.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshEntity.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsVirtualTopoMapper.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

namespace Exchange
{
    FITKAcousticsVTKGraphObjectModel::FITKAcousticsVTKGraphObjectModel(Interface::FITKAbsGeoCommand* modelData)
        : FITKAcousticsVTKGraphObject3D(modelData)
    {
        if (!modelData)
        {
            return;
        }

        // Intiailize the polygon offset.
        double po = FITKAcousticsVTKCommons::s_polygonOffsetCAD;
        m_polygonOffset = FITKAcousticsVTKCommons::GetRandomPolygonOffset(po, po + 1.);

        // Initialize.
        init();

        // Convert shape data.
        bool flag = generateDataSet();
        if (!flag)
        {
            return;
        }

        // Generate the shape actors.
        generateGraph();

        // Save the data type.
        m_graphInfo.Type = FITKAcousticsVTKCommons::ModelGraph;

        // Set the layer need to be rendered.
        setRenderLayer(0, 2);

        setTransparent(true);
    }

    bool FITKAcousticsVTKGraphObjectModel::test(QVariant& details)
    {
        if (!details.isValid())
        {
            return false;
        }

        return true;
    }

    FITKAcousticsVTKGraphObjectModel::~FITKAcousticsVTKGraphObjectModel()
    {
        // Delete the model data.
        deleteVtkObj(m_gridVertex);
        deleteVtkObj(m_gridEdge);
        deleteVtkObj(m_gridFace);
        deleteVtkObj(m_gridSolid);

        // Delete the addtional grids.
        deleteVtkObj(m_gridFaceEdges);
        deleteVtkObj(m_gridSolidEdges);
        
        // Delete face normals.
        deleteVtkObj(m_normalFacePoint);
        deleteVtkObj(m_normalSolidPoint);

        // Clear the maps.
        m_cellIdVertexIdMap.clear();
        m_cellIdEdgeIdMap.clear();
        m_cellIdFaceIdMap.clear();
        m_vertexIdCellIdMap.clear();
        m_edgeIdCellIdMap.clear();

        // Delete color maps.
        deleteObj(m_colorMapVertex);
        deleteObj(m_colorMapEdge);
        deleteObj(m_colorMapFace);
        deleteObj(m_colorMapSolid);

        // Set the pointer to NULL.
        m_triData = nullptr;
        m_topoMgr = nullptr;
    }

    void FITKAcousticsVTKGraphObjectModel::init()
    {
        // Create model grid data.
        //@{
        m_gridVertex = vtkUnstructuredGrid::New();
        m_gridVertex->SetPoints(vtkSmartPointer<vtkPoints>::New());
        m_gridEdge = vtkUnstructuredGrid::New();
        m_gridEdge->SetPoints(vtkSmartPointer<vtkPoints>::New());
        m_gridFace = vtkPolyData::New();
        m_gridFace->SetPoints(vtkSmartPointer<vtkPoints>::New());
        m_gridFace->SetPolys(vtkSmartPointer<vtkCellArray>::New());
        m_gridSolid = vtkPolyData::New();
        m_gridSolid->SetPoints(vtkSmartPointer<vtkPoints>::New());
        m_gridSolid->SetPolys(vtkSmartPointer<vtkCellArray>::New());       

        // Add the points normals for face grid.
        m_normalFacePoint = vtkDoubleArray::New();
        m_normalFacePoint->SetNumberOfComponents(3);
        m_gridFace->GetPointData()->SetNormals(m_normalFacePoint);

        // Add the points normals for face grid.
        m_normalSolidPoint = vtkDoubleArray::New();
        m_normalSolidPoint->SetNumberOfComponents(3);
        m_gridSolid->GetPointData()->SetNormals(m_normalSolidPoint);
        //@}

        // Additional grid data.
        //@{
        m_gridFaceEdges = vtkUnstructuredGrid::New();
        m_gridFaceEdges->SetPoints(vtkSmartPointer<vtkPoints>::New());
        m_gridSolidEdges = vtkUnstructuredGrid::New();
        m_gridSolidEdges->SetPoints(vtkSmartPointer<vtkPoints>::New());
        //}

        // Create the highlight selector.
        m_highlightSelector = new FITKAcousticsVTKGraphObjectSelect;
        m_addinGraphObjList.push_back(m_highlightSelector);
    }
    
    bool FITKAcousticsVTKGraphObjectModel::meshVSToVtkDataSet()
    {
        // Check the input data.
        if (!m_triData || !m_gridVertex || !m_gridEdge || !m_gridFace || !m_gridSolid)
        {
            return false;
        }         
        
        // Initialize the vertex grid.
        createVertexGrid();

        // Initialize the edge grid.
        createEdgeGrid();

        // Initialize the face grid.
        createFaceGrid();

        // Initialize the solid grid.
        createSolidGrid();

        return true;
    }

    void FITKAcousticsVTKGraphObjectModel::createVertexGrid()
    {
        // Check the data set and its points.
        if (!m_gridVertex || !m_triData)
        {
            return;
        }

        vtkPoints* points = m_gridVertex->GetPoints();
        if (!points)
        {
            return;
        }

        // Get the point shape topo manager.
        Interface::FITKShapeVirtualTopoManager* vsMgrPoint = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSPoint);
        if (!vsMgrPoint)
        {
            return;
        }

        // Get all points.
        const QHash<int, Interface::FITKGeoMeshVSPt*> & pointsHash = m_triData->getPointItems();
        QHashIterator<int, Interface::FITKGeoMeshVSPt*> iter(pointsHash);

        int ptIndex = -1;

        int nVerts = vsMgrPoint->getDataCount();
        for (int i = 0; i < nVerts; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoV = vsMgrPoint->getDataByIndex(i);
            if (!vTopoV)
            {
                continue;
            }

            // Check if the point is a root topo.
            int nParentTopo = vTopoV->getParentTopoCount();
            if (nParentTopo == 1)
            {
                // If the parent topo is assembly.
                Interface::FITKAbsVirtualTopo* topo = vTopoV->getParentTopo(0);
                if (topo->getShapeType() != Interface::FITKGeoEnum::VTopoShapeType::VSAssembly)
                {
                    continue;
                }
            }
            else if (nParentTopo > 1)
            {
                continue;
            }

            int pointId = vTopoV->getDataObjectID();

            Interface::FITKGeoMeshVSPt* pt = pointsHash[pointId];
            
            // Add point.
            ptIndex = points->InsertNextPoint(pt->x(), pt->y(), pt->z());

            // Add vertex cell.
            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            cell->InsertNextId(ptIndex);
            m_gridVertex->InsertNextCell(VTKCellType::VTK_VERTEX, cell);

            // Save the vertex id.
            m_cellIdVertexIdMap.push_back(pointId);
            m_vertexIdCellIdMap.insert(pointId, ptIndex);
        }
    }

    void FITKAcousticsVTKGraphObjectModel::createEdgeGrid()
    {
        // Check the data set and its points.
        if (!m_gridEdge || !m_triData)
        {
            return;
        }

        vtkPoints* points = m_gridEdge->GetPoints();
        if (!points)
        {
            return;
        }

        // Get the edge and wire shape topo manager.
        Interface::FITKShapeVirtualTopoManager* vsMgrEdge = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSEdge);
        Interface::FITKShapeVirtualTopoManager* vsMgrWire = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSWire);
        if (!vsMgrEdge || !vsMgrWire)
        {
            return;
        }

        // Get all edges.
        const QHash<int, Interface::FITKGeoMeshVSEdgeEntity*> & edgesHash = m_triData->getEdgeItems();
        QHashIterator<int, Interface::FITKGeoMeshVSEdgeEntity*> iter(edgesHash);

        int ptIndex = -1, cellIndex = -1;

        // Get the (root) edge topo.
        int nEdges = vsMgrEdge->getDataCount();
        for (int i = 0; i < nEdges; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoE = vsMgrEdge->getDataByIndex(i);
            if (!vTopoE)
            {
                continue;
            }

            // Check if the edge is a root topo.
            int nParentTopo = vTopoE->getParentTopoCount();
            if (nParentTopo == 1)
            {
                // If the parent topo is assembly.
                Interface::FITKAbsVirtualTopo* topo = vTopoE->getParentTopo(0);
                if (topo->getShapeType() != Interface::FITKGeoEnum::VTopoShapeType::VSAssembly)
                {
                    continue;
                }
            }
            else if (nParentTopo > 1)
            {
                continue;
            }

            int edgeId = vTopoE->getDataObjectID();

            // Get the edge mesh.
            Interface::FITKGeoMeshVSEdgeEntity* edge = edgesHash[edgeId];
            if (!edge)
            {
                continue;
            }

            // Get edge points.
            const QList<Interface::FITKGeoMeshVSPt*> & pts = edge->getPoints();

            // Get the node data and create poly line.
            vtkSmartPointer<vtkIdList> polyLineCell = vtkSmartPointer<vtkIdList>::New();

            for (Interface::FITKGeoMeshVSPt* pt : pts)
            {
                // Add point.
                ptIndex = points->InsertNextPoint(pt->x(), pt->y(), pt->z());
                polyLineCell->InsertNextId(ptIndex);
            }

            // Add cell.
            cellIndex = m_gridEdge->InsertNextCell(VTKCellType::VTK_POLY_LINE, polyLineCell);

            // Save the edge id.
            m_cellIdEdgeIdMap.push_back(edgeId);
            m_edgeIdCellIdMap.insert(edgeId, cellIndex);
        }

        // Get the (root) wire topo.
        int nWires = vsMgrWire->getDataCount();
        for (int i = 0; i < nWires; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoW = vsMgrWire->getDataByIndex(i);
            if (!vTopoW)
            {
                continue;
            }

            // Check if the wire is a root topo.
            int nParentTopo = vTopoW->getParentTopoCount();
            if (nParentTopo == 1)
            {
                // If the parent topo is assembly.
                Interface::FITKAbsVirtualTopo* topo = vTopoW->getParentTopo(0);
                if (topo->getShapeType() != Interface::FITKGeoEnum::VTopoShapeType::VSAssembly)
                {
                    continue;
                }
            }
            else if (nParentTopo > 1)
            {
                continue;
            }

            // int wireId = vTopoW->getDataObjectID();

            Interface::FITKVirtualTopoMapper vMapper;
            vMapper.mapTopo(vTopoW, Interface::FITKGeoEnum::VTopoShapeType::VSEdge);

            // Get all edges.
            int nWireEdges = vMapper.length();
            for (int j = 0; j < nWireEdges; j++)
            {
                Interface::FITKAbsVirtualTopo* vTopoE = vMapper.virtualTopo(j);
                if (!vTopoE)
                {
                    continue;
                }

                int edgeId = vTopoE->getDataObjectID();

                // Get the edge mesh.
                Interface::FITKGeoMeshVSEdgeEntity* edge = edgesHash[edgeId];
                if (!edge)
                {
                    continue;
                }

                // Get edge points.
                const QList<Interface::FITKGeoMeshVSPt*> & pts = edge->getPoints();

                // Get the node data and create poly line.
                vtkSmartPointer<vtkIdList> polyLineCell = vtkSmartPointer<vtkIdList>::New();

                for (Interface::FITKGeoMeshVSPt* pt : pts)
                {
                    // Add point.
                    ptIndex = points->InsertNextPoint(pt->x(), pt->y(), pt->z());
                    polyLineCell->InsertNextId(ptIndex);
                }

                // Add cell.
                cellIndex = m_gridEdge->InsertNextCell(VTKCellType::VTK_POLY_LINE, polyLineCell);

                // Save the edge id.
                m_cellIdEdgeIdMap.push_back(edgeId);
                m_edgeIdCellIdMap.insert(edgeId, cellIndex);
            }
        }
    }

    void FITKAcousticsVTKGraphObjectModel::createFaceGrid()
    {
        // Check the data set and its points.
        if (!m_gridFace || !m_gridFaceEdges || !m_triData)
        {
            return;
        }

        vtkPoints* points = m_gridFace->GetPoints();
        vtkPoints* pointsEdges = m_gridFaceEdges->GetPoints();
        if (!points || !pointsEdges)
        {
            return;
        }

        // Get all faces.
        const QHash<int, Interface::FITKGeoMeshVSFaceEntity*> & facesHash = m_triData->getFaceItems();

        // Get the face and shell shape topo manager.
        Interface::FITKShapeVirtualTopoManager* vsMgrFace = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSFace);
        Interface::FITKShapeVirtualTopoManager* vsMgrShell = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSShell);
        if (!vsMgrFace || !vsMgrShell)
        {
            return;
        }

        int ptIndexStart = 0;
        int cellIndex = -1;

        // Get the (root) face topo.
        int nFaces = vsMgrFace->getDataCount();
        for (int i = 0; i < nFaces; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoF = vsMgrFace->getDataByIndex(i);
            if (!vTopoF)
            {
                continue;
            }

            // Check if the face is a root topo.
            int nParentTopo = vTopoF->getParentTopoCount();
            if (nParentTopo == 1)
            {
                // If the parent topo is assembly.
                Interface::FITKAbsVirtualTopo* topo = vTopoF->getParentTopo(0);
                if (topo->getShapeType() != Interface::FITKGeoEnum::VTopoShapeType::VSAssembly)
                {
                    continue;
                }            
            }
            else if (nParentTopo > 1)
            {
                continue;
            }

            int faceId = vTopoF->getDataObjectID();

            // Get the face mesh.
            Interface::FITKGeoMeshVSFaceEntity* face = facesHash[faceId];
            if (!face)
            {
                continue;
            }

            // Get all points of the face mesh.
            const QList<Interface::FITKGeoMeshVSPt*> & facePoints = face->getPoints();
            for (Interface::FITKGeoMeshVSPt* facePoint : facePoints)
            {
                points->InsertNextPoint(facePoint->x(), facePoint->y(), facePoint->z());
            }

            // Get face mesh triangles.
            const QList<Interface::FITKGeoMeshVSTri*> & tris = face->getTriangles();
            for (Interface::FITKGeoMeshVSTri* tri : tris)
            {
                // Get points indice pf the triangle.
                const int* nodes = tri->getNode();

                // Get points index in VTK grid of vertice
                int ptIndex1 = ptIndexStart + nodes[0];
                int ptIndex2 = ptIndexStart + nodes[1];
                int ptIndex3 = ptIndexStart + nodes[2];

                // Add cell.
                vtkSmartPointer<vtkIdList> triCell = vtkSmartPointer<vtkIdList>::New();
                triCell->InsertNextId(ptIndex1);
                triCell->InsertNextId(ptIndex2);
                triCell->InsertNextId(ptIndex3);
                cellIndex = m_gridFace->InsertNextCell(VTKCellType::VTK_TRIANGLE, triCell);

                // Save the solid id.
                m_cellIdFaceIdMap.push_back(faceId);
                m_faceIdCellIdsHash[faceId].push_back(cellIndex);
            }

            // Update the point start index.
            ptIndexStart += facePoints.count();

            // For faces' edges.
            //@{
            addEdges(vTopoF, m_gridFaceEdges);
            //@}
        }

        // Get the (root) shell topo.
        int nShells = vsMgrShell->getDataCount();
        for (int i = 0; i < nShells; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoSh = vsMgrShell->getDataByIndex(i);
            if (!vTopoSh)
            {
                continue;
            }

            // Check if the shell is a root topo.
            int nParentTopo = vTopoSh->getParentTopoCount();
            if (nParentTopo == 1)
            {
                // If the parent topo is assembly.
                Interface::FITKAbsVirtualTopo* topo = vTopoSh->getParentTopo(0);
                if (topo->getShapeType() != Interface::FITKGeoEnum::VTopoShapeType::VSAssembly)
                {
                    continue;
                }
            }
            else if (nParentTopo > 1)
            {
                continue;
            }

            // int shellId = vTopoSh->getDataObjectID();

            Interface::FITKVirtualTopoMapper vMapper;
            vMapper.mapTopo(vTopoSh, Interface::FITKGeoEnum::VTopoShapeType::VSFace);

            // Get all faces.
            int nShellFaces = vMapper.length();
            for (int j = 0; j < nShellFaces; j++)
            {
                Interface::FITKAbsVirtualTopo* vTopoF = vMapper.virtualTopo(j);
                if (!vTopoF)
                {
                    continue;
                }

                int faceId = vTopoF->getDataObjectID();

                // Get the face mesh.
                Interface::FITKGeoMeshVSFaceEntity* face = facesHash[faceId];
                if (!face)
                {
                    continue;
                }

                // Get all points of the face mesh.
                const QList<Interface::FITKGeoMeshVSPt*> & facePoints = face->getPoints();
                for (Interface::FITKGeoMeshVSPt* facePoint : facePoints)
                {
                    points->InsertNextPoint(facePoint->x(), facePoint->y(), facePoint->z());
                }

                // Get face mesh triangles.
                const QList<Interface::FITKGeoMeshVSTri*> & tris = face->getTriangles();

                for (Interface::FITKGeoMeshVSTri* tri : tris)
                {
                    // Get points indice pf the triangle.
                    const int* nodes = tri->getNode();

                    // Get points index in VTK grid of vertice
                    int ptIndex1 = ptIndexStart + nodes[0];
                    int ptIndex2 = ptIndexStart + nodes[1];
                    int ptIndex3 = ptIndexStart + nodes[2];

                    // Add cell.
                    vtkSmartPointer<vtkIdList> triCell = vtkSmartPointer<vtkIdList>::New();
                    triCell->InsertNextId(ptIndex1);
                    triCell->InsertNextId(ptIndex2);
                    triCell->InsertNextId(ptIndex3);
                    cellIndex = m_gridFace->InsertNextCell(VTKCellType::VTK_TRIANGLE, triCell);

                    // Save the solid id.
                    m_cellIdFaceIdMap.push_back(faceId);
                    m_faceIdCellIdsHash[faceId].push_back(cellIndex);
                }

                // Update the point start index.
                ptIndexStart += facePoints.count();
            }

            // For shells' edges.
            //@{
            addEdges(vTopoSh, m_gridFaceEdges);
            //@}
        }

        // Add the points normals.
        addPointNormals(m_gridFace, m_normalFacePoint);
    }

    void FITKAcousticsVTKGraphObjectModel::createSolidGrid()
    {
        // Check the data set and its points.
        if (!m_gridSolid || !m_triData)
        {
            return;
        }

        vtkPoints* points = m_gridSolid->GetPoints();
        if (!points)
        {
            return;
        }

        // Get all faces.
        const QHash<int, Interface::FITKGeoMeshVSFaceEntity*> & facesHash = m_triData->getFaceItems();

        // Get the solid shape topo manager.
        Interface::FITKShapeVirtualTopoManager* vsMgrSolid = m_topoMgr->getShapeVirtualTopoManager(
            Interface::FITKGeoEnum::VTopoShapeType::VSSolid);
        if (!vsMgrSolid)
        {
            return;
        }

        int ptIndexStart = 0;
        int cellIndex = -1;

        // Get the (root) solid topo.
        int nSolids = vsMgrSolid->getDataCount();
        for (int i = 0; i < nSolids; i++)
        {
            Interface::FITKAbsVirtualTopo* vTopoS = vsMgrSolid->getDataByIndex(i);
            if (!vTopoS)
            {
                continue;
            }

            int solidId = vTopoS->getDataObjectID();

            Interface::FITKVirtualTopoMapper vMapper;
            vMapper.mapTopo(vTopoS, Interface::FITKGeoEnum::VTopoShapeType::VSFace);

            // Get all faces.
            int nFaces = vMapper.length();
            for (int j = 0; j < nFaces; j++)
            {
                Interface::FITKAbsVirtualTopo* vTopoF = vMapper.virtualTopo(j);
                if (!vTopoF)
                {
                    continue;
                }

                int faceId = vTopoF->getDataObjectID();

                // Get the face mesh.
                Interface::FITKGeoMeshVSFaceEntity* face = facesHash[faceId];
                if (!face)
                {
                    continue;
                }

                // Get all points of the face mesh.
                const QList<Interface::FITKGeoMeshVSPt*> & facePoints = face->getPoints();
                for (Interface::FITKGeoMeshVSPt* facePoint : facePoints)
                {
                    points->InsertNextPoint(facePoint->x(), facePoint->y(), facePoint->z());
                }

                // Get face mesh triangles.
                const QList<Interface::FITKGeoMeshVSTri*> & tris = face->getTriangles();

                for (Interface::FITKGeoMeshVSTri* tri : tris)
                {
                    // Get points indice pf the triangle.
                    const int* nodes = tri->getNode();

                    // Get points index in VTK grid of vertice
                    int ptIndex1 = ptIndexStart + nodes[0];
                    int ptIndex2 = ptIndexStart + nodes[1];
                    int ptIndex3 = ptIndexStart + nodes[2];

                    // Add cell.
                    vtkSmartPointer<vtkIdList> triCell = vtkSmartPointer<vtkIdList>::New();
                    triCell->InsertNextId(ptIndex1);
                    triCell->InsertNextId(ptIndex2);
                    triCell->InsertNextId(ptIndex3);
                    cellIndex = m_gridSolid->InsertNextCell(VTKCellType::VTK_TRIANGLE, triCell);

                    // Save the solid id.
                    m_cellIdSolidIdMap.push_back(solidId);
                    m_solidIdCellIdsHash[solidId].push_back(cellIndex);
                }

                // Update the point start index.
                ptIndexStart += facePoints.count();
            }

            // For solids' edges.
            //@{
            addEdges(vTopoS, m_gridSolidEdges);
            //@}
        }

        // Add the points normals.
        addPointNormals(m_gridSolid, m_normalSolidPoint);
    }

    void FITKAcousticsVTKGraphObjectModel::addPointNormals(vtkPolyData* polyData, vtkDoubleArray* normals)
    {
        if (!polyData || !normals)
        {
            return;
        }

        // For computing points nromals.
        vtkDoubleArray* tempCellNormals = vtkDoubleArray::New();
        tempCellNormals->SetNumberOfComponents(3);
        double tempNor3[3]{ 0., 0., 0. };

        // Calculate the cell normals.
        int nCells = polyData->GetNumberOfCells();
        for (int i = 0; i < nCells; i++)
        {
            // Calculate cell normals.
            vtkPolygon::ComputeNormal(polyData->GetCell(i)->GetPoints(), tempNor3);

            // Save the normals.
            tempCellNormals->InsertNextTuple3(tempNor3[0], tempNor3[1], tempNor3[2]);
        }

        // Calculate points normals for the face grid.
        normals->SetNumberOfTuples(polyData->GetNumberOfPoints());
        normals->FillComponent(0, 0);
        normals->FillComponent(1, 0);
        normals->FillComponent(2, 0);

        int cellId = 0;
        vtkIdType npts = 0;
#if VTK_MAJOR_VERSION < 9
        vtkIdType* pts = nullptr;
#else
        const vtkIdType* pts = nullptr;
#endif

        // Add two double array.
        auto addDouble3 = [&](double* v1, double* v2, double* result)
        {
            for (int i = 0; i < 3; i++)
            {
                result[i] = v1[i] + v2[i];
            }
        };

        double result[3]{ 0., 0., 0. };
        for (cellId = 0, polyData->GetPolys()->InitTraversal(); polyData->GetPolys()->GetNextCell(npts, pts); ++cellId)
        {
            double* norCellCurrent = tempCellNormals->GetTuple3(cellId);

            for (vtkIdType i = 0; i < npts; ++i)
            {
                double* norPtCurrent = normals->GetTuple3(pts[i]);

                // Add normals.
                addDouble3(norPtCurrent, norCellCurrent, result);
                normals->SetTuple3(pts[i], result[0], result[1], result[2]);
            }
        }

        double flipDirection = 1.0;
        for (vtkIdType i = 0; i < polyData->GetNumberOfPoints(); ++i)
        {
            double* ptNormal = normals->GetTuple3(i);
            const double length = sqrt(pow(ptNormal[0], 2) + pow(ptNormal[1], 2) + pow(ptNormal[2], 2)) * flipDirection;
            if (!qFuzzyCompare(length, 0.))
            {
                ptNormal[0] /= length;
                ptNormal[1] /= length;
                ptNormal[2] /= length;
            }

            normals->SetTuple3(i, ptNormal[0], ptNormal[1], ptNormal[2]);
        }

        // Delete temp data.
        tempCellNormals->Delete();
    }

    void FITKAcousticsVTKGraphObjectModel::update(bool forceUpdate)
    {
        Interface::FITKAbsGeoCommand* modelData = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (!modelData)
        {
            return;
        }

        // Get the abastract shape agent.
        Interface::FITKAbsGeoShapeAgent* shapeAgent = modelData->getShapeAgent();
        if (!shapeAgent)
        {
            return;
        }

        if (!shapeAgent || m_testFlag)
        {
            return;
        }

        // Update visibility first.
        updateVisibility();

        // Check if the shape has been changed.
        QVariant newState;
        shapeAgent->createShapeState(newState);
        if (newState == m_shapeState && !forceUpdate)
        {
            return;
        }

        // Clear data set first.
        clearData();

        shapeAgent->buildVirtualTopo();

        // Re-generate the shape.
        generateDataSet();
    }

    void FITKAcousticsVTKGraphObjectModel::updateVisibility()
    {
        // Get the runtime settings for visibility.
        bool showCAD = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_CAD, true);
        bool showGeom = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_GEOMETRY, true);
        bool showGeomVerts = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_GEOM_VERTS, true);
        bool showGeomEdges = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_GEOM_EDGES, true);
        bool showGeomFaces = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_GEOM_FACES, true);
        bool showGeomSolids = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_GEOM_SOLIDS, true);

        bool mainFlag = this->Superclass::getDataVisibility() && showGeom && showCAD;

        // Update the visibility with the flags.
        //@{
        // Show or hide vertex.
        if (m_fActorVertex)
        {
            m_fActorVertex->SetVisibility(mainFlag && showGeomVerts);
        }

        // Show or hide edge.
        if (m_fActorEdge)
        {
            m_fActorEdge->SetVisibility(mainFlag && showGeomEdges);
        }

        // Show or hide face.
        if (m_fActorFace)
        {
            m_fActorFace->SetVisibility(mainFlag && showGeomFaces);
        }

        if (m_fActorFaceEdge)
        {
            m_fActorFaceEdge->SetVisibility(mainFlag && showGeomFaces);
        }

        // Show or hide solid.
        if (m_fActorSolid)
        {
            m_fActorSolid->SetVisibility(mainFlag && showGeomSolids);
        }

        if (m_fActorSolidEdge)
        {
            m_fActorSolidEdge->SetVisibility(mainFlag && showGeomSolids);
        }
        //@}

        // The highlightor.
        if (m_highlightSelector)
        {
            m_highlightSelector->setVisible(mainFlag && getDataVisibility() && (m_isHighlighting || m_isAdvHighlighting));
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setVisible(bool visibility)
    {
        // Show or hide vertex.
        if (m_fActorVertex)
        {
            m_fActorVertex->SetVisibility(m_showVert && visibility);
        }

        // Show or hide edge.
        if (m_fActorEdge)
        {
            m_fActorEdge->SetVisibility(m_showEdge && visibility);
        }

        // Show or hide face.
        if (m_fActorFace)
        {
            m_fActorFace->SetVisibility(m_showFace && visibility);
        }

        if (m_fActorFaceEdge)
        {
            m_fActorFaceEdge->SetVisibility(m_showFace && visibility);
        }

        // Show or hide solid.
        if (m_fActorSolid)
        {
            m_fActorSolid->SetVisibility(m_showSolid && visibility);
        }

        if (m_fActorSolidEdge)
        {
            m_fActorSolidEdge->SetVisibility(m_showSolid && visibility);
        }

        // The highlightor.
        if (m_highlightSelector)
        {
            m_highlightSelector->setVisible(visibility && getDataVisibility() && (m_isHighlighting || m_isAdvHighlighting));
        }

        // Save the visibility.
        m_globalVisibility = visibility;
    }

    void FITKAcousticsVTKGraphObjectModel::setVerticesVisible(bool visibility)
    {
        // Show or hide vertex.
        if (m_fActorVertex)
        {
            m_fActorVertex->SetVisibility(m_globalVisibility && m_showVert &&
                visibility && !m_vertexIdCellIdMap.isEmpty());
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setEdgesVisible(bool visibility)
    {
        // Show or hide edge.
        if (m_fActorEdge)
        {
            m_fActorEdge->SetVisibility(m_globalVisibility && m_showEdge &&
                visibility && !m_edgeIdCellIdMap.isEmpty());
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setFacesVisible(bool visibility)
    {
        bool showFace = m_globalVisibility && m_showFace && 
            visibility && !m_faceIdCellIdsHash.isEmpty();

        // Show or hide face.
        if (m_fActorFace)
        {
            m_fActorFace->SetVisibility(showFace);
        }

        if (m_fActorFaceEdge)
        {
            m_fActorFaceEdge->SetVisibility(showFace);
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setSolidsVisible(bool visibility)
    {
        bool showSolid = m_globalVisibility && m_showSolid &&
            visibility && !m_solidIdCellIdsHash.isEmpty();

        // Show or hide solid.
        if (m_fActorSolid)
        {
            m_fActorSolid->SetVisibility(showSolid);
        }

        if (m_fActorSolidEdge)
        {
            m_fActorSolidEdge->SetVisibility(showSolid);
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setTransparent(bool isOn)
    {
        // Get the opacity.
        double opa = isOn ? 1. - FITKAcousticsVTKCommons::s_defaultModelTransparency : 1.;

        for (vtkProp* prop : m_actorList)
        {
            FITKAcousticsVTKGraphActor* fActor = FITKAcousticsVTKGraphActor::SafeDownCast(prop);
            if (fActor)
            {
                fActor->GetProperty()->SetOpacity(opa);
            }
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setColor(QColor color, FITKAcousticsVTKCommons::ShapeType type, int index)
    {
        switch (type)
        {
        case FITKAcousticsVTKCommons::ModelVertex:
        {
            // Get the vertex cell ( vertex  cell ) id by the given vertex id.
            int cellId = -1;
            if (!m_vertexIdCellIdMap.contains(index) || !m_colorMapVertex)
            {
                return;
            }

            cellId = m_vertexIdCellIdMap[index];
            m_colorMapVertex->setCellsColor(c_defaultArrName, { cellId }, color);
            break;
        }
        case FITKAcousticsVTKCommons::ModelEdge:
        {
            // Get the edge cell ( poly-line cell ) id by the given edge id.
            int cellId = -1;
            if (!m_edgeIdCellIdMap.contains(index) || !m_colorMapEdge)
            {
                return;
            }

            cellId = m_edgeIdCellIdMap[index];
            m_colorMapEdge->setCellsColor(c_defaultArrName, { cellId }, color);
            break;
        }
        case FITKAcousticsVTKCommons::ModelFace:
        {
            // Get the face cell ( triangle cell ) ids by the given face id.
            if (!m_faceIdCellIdsHash.contains(index) || !m_colorMapFace)
            {
                return;
            }

            const QVector<int> & cellIds = m_faceIdCellIdsHash[index];
            m_colorMapFace->setCellsColor(c_defaultArrName, cellIds.toList(), color);
            break;
        }
        case FITKAcousticsVTKCommons::ModelSolid:
        {
            // Get the solid cell ( triangle cell ) ids by the given solid id.
            if (!m_solidIdCellIdsHash.contains(index) || !m_colorMapSolid)
            {
                return;
            }

            const QVector<int> & cellIds = m_solidIdCellIdsHash[index];
            m_colorMapSolid->setCellsColor(c_defaultArrName, cellIds.toList(), color);
            break;
        }
        default:
            return;
        }
    }

    void FITKAcousticsVTKGraphObjectModel::highlight(FITKAcousticsVTKCommons::ShapeType type, QColor color)
    {
        // Show the actor and initialize the data.
        if (!m_highlightSelector)
        {
            return;
        }

        // Default highlight all faces.
        if (type == FITKAcousticsVTKCommons::ShapeType::ShapeTypeNone)
        {
            type = FITKAcousticsVTKCommons::ShapeType::ModelFace;
        }

        vtkDataSet* meshDataSet = getMesh(type);
        if (!meshDataSet)
        {
            return;
        }

        QVector<int> indice;
        for (int i = 0; i < meshDataSet->GetNumberOfCells(); i++)
        {
            indice.push_back(i);
        }

        // Check the color.
        if (!color.isValid())
        {
            color = Qt::red;
        }

        m_highlightSelector->setColor(color);
        m_highlightSelector->setSelectData(meshDataSet, indice, type);
        m_highlightSelector->setVisible(getDataVisibility());

        // Save the highlight flag.
        this->Superclass::highlight(type, color);
    }

    void FITKAcousticsVTKGraphObjectModel::disHighlight()
    {
        // Hide the actor only.
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
            m_highlightSelector->setVisible(false);
        }

        // Save the highlight flag.
        this->Superclass::disHighlight();
    }

    void FITKAcousticsVTKGraphObjectModel::advanceHighlight(FITKAcousticsVTKCommons::ShapeType type, QVector<int> indice, QColor color)
    {
        // Show the actor and initialize the data.
        if (!m_highlightSelector)
        {
            return;
        }

        if (indice.isEmpty())
        {
            return;
        }

        vtkDataSet* meshDataSet = getMesh(type);
        if (!meshDataSet)
        {
            return;
        }

        // Get the model shape type.
        FITKAcousticsVTKCommons::ShapeMeshAbsEnum shapeEnum;
        switch (type)
        {
        case FITKAcousticsVTKCommons::ModelVertex:
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_VERTEX;
            break;
        case FITKAcousticsVTKCommons::ModelEdge:
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_EDGE;
            break;
        case FITKAcousticsVTKCommons::ModelFace:
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_FACE;
            break;
        case FITKAcousticsVTKCommons::ModelSolid:
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SOLID;
            break;
        case FITKAcousticsVTKCommons::ShapeTypeNone:
        case FITKAcousticsVTKCommons::MeshNode:
        case FITKAcousticsVTKCommons::MeshElement:
        default:
            return;
        }

        // Get the cell ids in VTK.
        int nCells = meshDataSet->GetNumberOfCells();
        QVector<int> cellFlags;
        cellFlags.resize(nCells);
        cellFlags.fill(0);

        // Get VTK ids by Shape ids.
        for (const int & index : indice)
        {
            QVector<int> vtkIds = getVTKCellIdsByShapeId(index, shapeEnum);

            for (const int & vtkId : vtkIds)
            {
                cellFlags[vtkId] = 1;
            }
        }

        QVector<int> vtkIndice;
        for (int i = 0; i < cellFlags.count(); i++)
        {
            if (cellFlags[i])
            {
                vtkIndice.push_back(i);
            }
        }

        // Check the color.
        if (!color.isValid())
        {
            color = Qt::red;
        }

        m_highlightSelector->setColor(color);
        m_highlightSelector->setSelectData(meshDataSet, vtkIndice, type);
        m_highlightSelector->setVisible(getDataVisibility());

        // Save the highlight flag.
        this->Superclass::advanceHighlight(type, indice, color);
    }

    void FITKAcousticsVTKGraphObjectModel::disAdvanceHighlight()
    {
        // Clear data and hide the actor.
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
            m_highlightSelector->setVisible(false);
        }

        // Save the highlight flag.
        this->Superclass::disAdvanceHighlight();
    }

    int FITKAcousticsVTKGraphObjectModel::getNumberOf(FITKAcousticsVTKCommons::ShapeType type)
    {
        if (!m_triData)
        {
            return 0;
        }

        switch (type)
        {
        case FITKAcousticsVTKCommons::ModelVertex:
            return m_vertexIdCellIdMap.count();
        case FITKAcousticsVTKCommons::ModelEdge:
            return m_edgeIdCellIdMap.count();
        case FITKAcousticsVTKCommons::ModelFace:
            return m_faceIdCellIdsHash.count();
        case FITKAcousticsVTKCommons::ModelSolid:
            return m_solidIdCellIdsHash.count();
        case FITKAcousticsVTKCommons::ShapeTypeNone:
        case FITKAcousticsVTKCommons::MeshNode:
        case FITKAcousticsVTKCommons::MeshElement:      
        default:
            return 0;
        }
    }

    void FITKAcousticsVTKGraphObjectModel::setPickMode(FITKAcousticsVTKCommons::ShapePickMode mode)
    {
        // Lambda for set actor pickable.
        auto setActorPickable = [=](FITKAcousticsVTKGraphActor* fActor, bool isOn)
        {
            if (fActor)
            {
                fActor->SetPickable(isOn);
            }
        };

        switch (mode)
        {
        case FITKAcousticsVTKCommons::PickNone:
            setActorPickable(m_fActorVertex, false);
            setActorPickable(m_fActorEdge, false);
            setActorPickable(m_fActorFace, false);
            setActorPickable(m_fActorSolid, false);
            break;
        case FITKAcousticsVTKCommons::PickVertex:
            setActorPickable(m_fActorVertex, true);
            setActorPickable(m_fActorEdge, false);
            setActorPickable(m_fActorFace, false);
            setActorPickable(m_fActorSolid, false);
            break;
        case FITKAcousticsVTKCommons::PickEdge:
            setActorPickable(m_fActorVertex, false);
            setActorPickable(m_fActorEdge, true);
            setActorPickable(m_fActorFace, false);
            setActorPickable(m_fActorSolid, false);
            break;
        case FITKAcousticsVTKCommons::PickFace:
            setActorPickable(m_fActorVertex, false);
            setActorPickable(m_fActorEdge, false);
            setActorPickable(m_fActorFace, true);
            setActorPickable(m_fActorSolid, false);
            break;
        case FITKAcousticsVTKCommons::PickSolid:
            setActorPickable(m_fActorVertex, false);
            setActorPickable(m_fActorEdge, false);
            setActorPickable(m_fActorFace, false);
            setActorPickable(m_fActorSolid, true);
            break;
        case FITKAcousticsVTKCommons::PickAll:
            setActorPickable(m_fActorVertex, true);
            setActorPickable(m_fActorEdge, true);
            setActorPickable(m_fActorFace, true);
            setActorPickable(m_fActorSolid, true);
            break;
        default:
            return;
        }

        // Save the pick mode.
        this->Superclass::setPickMode(mode);
    }

    int FITKAcousticsVTKGraphObjectModel::getShapeIdByVTKCellId(int vtkCellId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        int id = -1;
        if (vtkCellId < 0)
        {
            return id;
        }

        switch (topAbsShapeType)
        {
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SOLID:
        {
            // Try to get the solid.
            if (m_cellIdSolidIdMap.count() <= vtkCellId)
            {
                break;
            }

            // Get the solid id.
            id = m_cellIdSolidIdMap[vtkCellId];

            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_FACE:
        {
            // Try to get the face.
            if (m_cellIdFaceIdMap.count() <= vtkCellId)
            {
                break;
            }

            // Get the face id.
            id = m_cellIdFaceIdMap[vtkCellId];

            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_EDGE:
        {
            // Try to get the edge.
            if (m_cellIdEdgeIdMap.count() <= vtkCellId)
            {
                break;
            }

            // Get the edge id.
            id = m_cellIdEdgeIdMap[vtkCellId];

            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_VERTEX:
        {
            // Try to get the vertex.
            if (m_cellIdVertexIdMap.count() <= vtkCellId)
            {
                break;
            }

            // Get the vertex id.
            id = m_cellIdVertexIdMap[vtkCellId];

            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPOUND:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPSOLID:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHELL:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_WIRE:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHAPE:
        default:
            break;
        }

        return id;
    }

    const QVector<int> FITKAcousticsVTKGraphObjectModel::getVTKCellIdsByShapeId(int shapeId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        QVector<int> cellIds;

        switch (topAbsShapeType)
        {
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SOLID:
        {
            if (!m_solidIdCellIdsHash.contains(shapeId))
            {
                break;
            }

            // Get the solid's cell ids.
            cellIds = m_solidIdCellIdsHash[shapeId];
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_FACE:
        {
            if (!m_faceIdCellIdsHash.contains(shapeId))
            {
                break;
            }

            // Get the face's cell ids.
            cellIds = m_faceIdCellIdsHash[shapeId];
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_EDGE:
        {
            if (!m_edgeIdCellIdMap.contains(shapeId))
            {
                break;
            }

            // Get the edge's cell id.( Poly line cell )
            cellIds.push_back(m_edgeIdCellIdMap[shapeId]);
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_VERTEX:
        {
            if (!m_vertexIdCellIdMap.contains(shapeId))
            {
                break;
            }

            // Get the vertex's cell id.( Vertex cell )
            cellIds.push_back(m_vertexIdCellIdMap[shapeId]);
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPOUND:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPSOLID:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHELL:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_WIRE:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHAPE:
        default:
            break;
        }

        return cellIds;
    }

    const QVector<int> FITKAcousticsVTKGraphObjectModel::getVTKCellIdsByVTKCellId(int cellId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        QVector<int> cellIds;

        switch (topAbsShapeType)
        {
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SOLID:
        {
            if (cellId >= m_cellIdSolidIdMap.count())
            {
                break;
            }

            // Get the face id.
            int faceId = m_cellIdSolidIdMap[cellId];
            cellIds = m_solidIdCellIdsHash[faceId];
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_FACE:
        {
            if (cellId >= m_cellIdFaceIdMap.count())
            {
                break;
            }

            // Get the face id.
            int faceId = m_cellIdFaceIdMap[cellId];
            cellIds = m_faceIdCellIdsHash[faceId];
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_EDGE:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_VERTEX:
        {
            // The edge and vertex cell id is the given cell id.
            cellIds.push_back(cellId);
            break;
        }
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPOUND:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_COMPSOLID:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHELL:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_WIRE:
        case FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_SHAPE:
        default:
            break;
        }

        return cellIds;
    }

    vtkDataSet* FITKAcousticsVTKGraphObjectModel::getMesh(FITKAcousticsVTKCommons::ShapeType type)
    {
        // Get the mesh data for extractor.
        switch (type)
        {
        case FITKAcousticsVTKCommons::ModelVertex:
            return m_gridVertex;
        case FITKAcousticsVTKCommons::ModelEdge:
            return m_gridEdge;
        case FITKAcousticsVTKCommons::ModelFace:
            return m_gridFace;
        case FITKAcousticsVTKCommons::ModelSolid:
            return m_gridSolid;
        default:
            break;
        }

        return nullptr;
    }

    bool FITKAcousticsVTKGraphObjectModel::generateDataSet()
    {
        Interface::FITKAbsGeoCommand* modelData = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (!modelData)
        {
            return false;
        }

        // Get the abastract shape agent.
        Interface::FITKAbsGeoShapeAgent* shapeAgent = modelData->getShapeAgent();
        if (!shapeAgent)
        {
            return false;
        }

        // Trianglate.
        shapeAgent->triangulation();

        // Get the trianglation of the shape.
        Interface::FITKGeometryMeshVS* triData = shapeAgent->getMeshVS();
        if (!triData)
        {
            return false;
        }

        // Save the trianglation data and the topo-manager.
        m_triData = triData;
        m_topoMgr = shapeAgent->getVirtualTopoManager();

        // Save the hash code of the shape.
        QVariant newState;
        shapeAgent->createShapeState(newState);
        m_shapeState = newState;

        bool flag = meshVSToVtkDataSet();
        return flag;
    }

    void FITKAcousticsVTKGraphObjectModel::generateGraph()
    {
        if (!m_gridVertex || !m_gridEdge || !m_gridFace || !m_gridSolid)
        {
            return;
        }

        // Create vertex actor.
        m_fActorVertex = FITKAcousticsVTKGraphActor::New();
        m_fActorVertex->setGraphObject(this);
        m_fActorVertex->setActorType(ActorType::VertexActor);
        m_fActorVertex->SetPickable(false);
        m_fActorVertex->SetVisibility(true);
        m_fActorVertex->GetProperty()->SetPointSize(5);
        m_fActorVertex->GetProperty()->SetRepresentation(2);
        m_fActorVertex->setInputDataObject(m_gridVertex);
        addActor(m_fActorVertex);

        // Create edge actor.
        m_fActorEdge = FITKAcousticsVTKGraphActor::New();
        m_fActorEdge->setGraphObject(this);
        m_fActorEdge->setActorType(ActorType::EdgeActor);
        m_fActorEdge->SetPickable(false);
        m_fActorEdge->SetVisibility(true);
        m_fActorEdge->GetProperty()->SetLineWidth(2);
        m_fActorEdge->GetProperty()->SetRepresentation(1);
        m_fActorEdge->setInputDataObject(m_gridEdge);
        addActor(m_fActorEdge);

        // Create face actor.
        m_fActorFace = FITKAcousticsVTKGraphActor::New();
        m_fActorFace->setGraphObject(this);
        m_fActorFace->setActorType(ActorType::SurfaceActor);
        m_fActorFace->SetPickable(false);
        m_fActorFace->SetVisibility(true);
        m_fActorFace->GetProperty()->SetRepresentation(2);
        m_fActorFace->GetProperty()->SetEdgeVisibility(false);
        m_fActorFace->GetProperty()->SetLineWidth(1.);
        m_fActorFace->setInputDataObject(m_gridFace);
        m_fActorFace->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActorFace);

        // Create solid actor.
        m_fActorSolid = FITKAcousticsVTKGraphActor::New();
        m_fActorSolid->setGraphObject(this);
        m_fActorSolid->setActorType(ActorType::SolidActor);
        m_fActorSolid->SetPickable(false);
        m_fActorSolid->SetVisibility(true);
        m_fActorSolid->GetProperty()->SetRepresentation(2);
        m_fActorSolid->GetProperty()->SetEdgeVisibility(false);
        m_fActorSolid->GetProperty()->SetLineWidth(1.);
        m_fActorSolid->setInputDataObject(m_gridSolid);
        m_fActorSolid->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActorSolid);

        // Create additional actors.
        //@{
        m_fActorFaceEdge = FITKAcousticsVTKGraphActor::New();
        m_fActorFaceEdge->setGraphObject(this);
        m_fActorFaceEdge->setActorType(ActorType::EdgeActor);
        m_fActorFaceEdge->SetPickable(false);
        m_fActorFaceEdge->SetVisibility(true);
        m_fActorFaceEdge->GetProperty()->SetRepresentation(1);
        m_fActorFaceEdge->GetProperty()->SetEdgeVisibility(true);
        m_fActorFaceEdge->GetProperty()->SetLineWidth(1.);
        m_fActorFaceEdge->setInputDataObject(m_gridFaceEdges);
        addActor(m_fActorFaceEdge);

        m_fActorSolidEdge = FITKAcousticsVTKGraphActor::New();
        m_fActorSolidEdge->setGraphObject(this);
        m_fActorSolidEdge->setActorType(ActorType::EdgeActor);
        m_fActorSolidEdge->SetPickable(false);
        m_fActorSolidEdge->SetVisibility(true);
        m_fActorSolidEdge->GetProperty()->SetRepresentation(1);
        m_fActorSolidEdge->GetProperty()->SetEdgeVisibility(true);
        m_fActorSolidEdge->GetProperty()->SetLineWidth(1.);
        m_fActorSolidEdge->setInputDataObject(m_gridSolidEdges);
        addActor(m_fActorSolidEdge);

        double edgeColor3[3]{ 0., 0., 0. };
        FITKAcousticsVTKCommons::QColorToDouble3(FITKAcousticsVTKCommons::s_geoEdgeColor, edgeColor3);
        m_fActorFaceEdge->GetProperty()->SetColor(edgeColor3);
        m_fActorSolidEdge->GetProperty()->SetColor(edgeColor3);
        //@}

        // Set the colors.
        //@{
        m_colorMapVertex = new FITKAcousticsVTKColorMap;
        m_colorMapEdge = new FITKAcousticsVTKColorMap;
        m_colorMapFace = new FITKAcousticsVTKColorMap;
        m_colorMapSolid = new FITKAcousticsVTKColorMap;

        m_colorMapVertex->setInputData(m_gridVertex);
        m_colorMapEdge->setInputData(m_gridEdge);
        m_colorMapFace->setInputData(m_gridFace);
        m_colorMapSolid->setInputData(m_gridSolid);

        m_colorMapVertex->setColor(c_defaultArrName, FITKAcousticsVTKCommons::s_geoVertexColor);
        m_colorMapEdge->setColor(c_defaultArrName, FITKAcousticsVTKCommons::s_geoEdgeColor);
        m_colorMapFace->setColor(c_defaultArrName, FITKAcousticsVTKCommons::s_geoFaceColor);
        m_colorMapSolid->setColor(c_defaultArrName, FITKAcousticsVTKCommons::s_geoSolidColor);
        //@}

        // Enable color arrays.
        //@{
        m_fActorVertex->setScalarVisibility(true);
        m_fActorEdge->setScalarVisibility(true);
        m_fActorFace->setScalarVisibility(true);
        m_fActorSolid->setScalarVisibility(true);

        m_fActorVertex->setScalarModeToUseCellFieldData();
        m_fActorEdge->setScalarModeToUseCellFieldData();
        m_fActorFace->setScalarModeToUseCellFieldData();
        m_fActorSolid->setScalarModeToUseCellFieldData();

        m_colorMapVertex->update();
        m_colorMapEdge->update();
        m_colorMapFace->update();
        m_colorMapSolid->update();

        m_fActorVertex->selectScalarArray(c_defaultArrName);
        m_fActorEdge->selectScalarArray(c_defaultArrName);
        m_fActorFace->selectScalarArray(c_defaultArrName);
        m_fActorSolid->selectScalarArray(c_defaultArrName);
        //@}
    }

    void FITKAcousticsVTKGraphObjectModel::clearData()
    {
        // Reset all data set.
        resetVtkObj(m_gridVertex);
        resetVtkObj(m_gridEdge);
        resetVtkObj(m_gridFace);
        resetVtkObj(m_gridSolid);
        resetVtkObj(m_gridFaceEdges);
        resetVtkObj(m_gridSolidEdges);

        resetVtkObj(m_gridVertex->GetPoints());
        resetVtkObj(m_gridEdge->GetPoints());
        resetVtkObj(m_gridFace->GetPoints());
        resetVtkObj(m_gridSolid->GetPoints());
        resetVtkObj(m_gridFaceEdges->GetPoints());
        resetVtkObj(m_gridSolidEdges->GetPoints());

        // Clear normals.
        resetVtkObj(m_normalFacePoint);
        resetVtkObj(m_normalSolidPoint);

        // Clear the maps.
        m_cellIdVertexIdMap.clear();
        m_cellIdEdgeIdMap.clear();
        m_cellIdFaceIdMap.clear();
        m_vertexIdCellIdMap.clear();
        m_edgeIdCellIdMap.clear();
        m_cellIdSolidIdMap.clear();
        m_faceIdCellIdsHash.clear();
        m_solidIdCellIdsHash.clear();

        // Clear color maps.
        m_colorMapVertex->clear();
        m_colorMapEdge->clear();
        m_colorMapFace->clear();
        m_colorMapSolid->clear();

        // Clear the selector.
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
        }
    }

    void FITKAcousticsVTKGraphObjectModel::addEdges(Interface::FITKAbsVirtualTopo* vTopo, vtkUnstructuredGrid* ugrid)
    {
        if (!m_triData || !ugrid)
        {
            return;
        }

        vtkPoints* points = ugrid->GetPoints();
        if (!points)
        {
            return;
        }

        const QHash<int, Interface::FITKGeoMeshVSEdgeEntity*> & edgesHash = m_triData->getEdgeItems();

        Interface::FITKVirtualTopoMapper vMapper;
        vMapper.mapTopo(vTopo, Interface::FITKGeoEnum::VTopoShapeType::VSEdge);

        // Get all faces.
        int ptIndex = -1;
        int nEdges = vMapper.length();
        for (int j = 0; j < nEdges; j++)
        {
            Interface::FITKAbsVirtualTopo* vTopoE = vMapper.virtualTopo(j);
            if (!vTopoE)
            {
                continue;
            }

            int edgeId = vTopoE->getDataObjectID();

            // Get the edge mesh.
            Interface::FITKGeoMeshVSEdgeEntity* edge = edgesHash[edgeId];
            if (!edge)
            {
                continue;
            }

            // Get edge points.
            const QList<Interface::FITKGeoMeshVSPt*> & pts = edge->getPoints();

            // Get the node data and create poly line.
            vtkSmartPointer<vtkIdList> polyLineCell = vtkSmartPointer<vtkIdList>::New();

            for (Interface::FITKGeoMeshVSPt* pt : pts)
            {
                // Add point.
                ptIndex = points->InsertNextPoint(pt->x(), pt->y(), pt->z());
                polyLineCell->InsertNextId(ptIndex);
            }

            // Add cell.
            ugrid->InsertNextCell(VTKCellType::VTK_POLY_LINE, polyLineCell);
        }
    }
}   // namespace Exchange